<template>
  <div
    id="canvas"
    @touchend="getinputPosition"
    ref="canvas"
    style="
      position: absolute;
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      margin: 0;
      padding: 0;
      background-repeat: no-repeat;
      background-size: cover;
      background-position: center;
    "
  >
    <textarea
      id="useKeyborad"
      type="text"
      @keyup="inputKeyBorad"
      @input="sendWord"
      v-if="showKeyBoard"
      v-model="inputForKeyBorad"
      style="
        position: absolute;
        opacity: 0;
        color: black;
        border: solid 1px black;
      "
      :style="{
        top: inputForKeyBoradTop + 'px',
        left: inputForKeyBoradLeft + 'px',
      }"
    />
    <div
      v-if="pageInfo != null && pageInfo.pageBackgroundImage != null"
      style="
        position: absolute;
        width: 100%;
        height: 100%;
        background-repeat: no-repeat;
        background-size: 100% 100%;
        background-position: center;
      "
      :style="{
        backgroundImage:
          'url(' +
          'http://' +
          resourceIp +
          ':8094/' +
          pageInfo.pageBackgroundImage +
          ')',
      }"
    ></div>
    <div v-for="(item, index) in variableSet.buttonList" :key="index">
      <button
        @click="executeCommandForClick(item)"
        v-show="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        class="MyButton"
        style="
          position: absolute;
          margin: 0;
          background-repeat: no-repeat;
          background-position: center;
          background-color: transparent;
          border: 0;
          outline: 0;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        "
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z + '',
          backgroundImage:
            'url(' + 'http://' + resourceIp + ':8094/' + item.background + ')',
          backgroundSize: item.w + 'px ' + item.h + 'px',
          fontSize: item.fontSize + 'px',
          color: item.fontColor,
          backgroundColor:
            item.backgroundColor == null ? 'transparent' : item.backgroundColor,
          borderRadius: item.borderCorner + 'px',
        }"
      >
        {{
          languageIndex == 0
            ? item.textChinese
            : languageIndex == 1
            ? item.textTraditional
            : item.textEnglish
        }}
      </button>
    </div>
    <div v-for="(item, index) in variableSet.switchList" :key="index">
      <van-switch
        style="position: absolute"
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z,
        }"
        :value="variableSet[item.switchVariable]"
        :active-value="item.switchVariableValue"
        :size="item.h + 'px'"
        :active-color="item.activeColor == null ? '#ee0a24' : item.activeColor"
        :inactive-color="
          item.unActiveColor == null ? '#dcdee0' : item.unActiveColor
        "
        @input="onInput(index)"
      />
    </div>

    <div v-for="(item, index) in variableSet.sliderList" :key="index">
      <van-slider
        @change="changeSlider(item)"
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        :vertical="item.vertical"
        v-model="variableSet[item.sliderVariable]"
        :inactive-color="item.railBackground"
        :bar-height="item.vertical ? item.w + 'px' : item.h + 'px'"
        :active-color="item.railProgressColor"
        style="position: absolute"
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z + '',
          border:
            'solid ' + item.railBorderWidth + 'px ' + item.railBorderColor,
          borderRadius: item.railBorderRoundCorner + 'px',
        }"
        :min="item.min"
        :max="item.max"
      >
        <template #button>
          <img
            v-if="item.sliderBackground != null"
            :src="'http://' + resourceIp + ':8094/' + item.sliderBackground"
            :style="{
              width: item.sliderWidth + 'px',
              height: item.sliderHeight + 'px',
              marginLeft: item.sliderMarginLeft + 'px',
              marginRight: item.sliderMarginRight + 'px',
              marginTop: item.sliderMarginTop + 'px',
              marginBottom: item.sliderMarginBottom + 'px',
            }"
            draggable="false"
          />
          <div
            v-if="item.sliderBackground == null"
            :style="{
              width: item.sliderWidth + 'px',
              height: item.sliderHeight + 'px',
              marginLeft: item.sliderMarginLeft + 'px',
              marginRight: item.sliderMarginRight + 'px',
              marginTop: item.sliderMarginTop + 'px',
              marginBottom: item.sliderMarginBottom + 'px',
              backgroundColor: item.sliderBackgroundColor,
              borderRadius: item.sliderBorderRadius + 'px',
            }"
            draggable="false"
          ></div>
        </template>
      </van-slider>
    </div>

    <div v-for="(item, index) in variableSet.textViewList" :key="index">
      <textarea
        @change="changeSlider(item)"
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        v-model="
          languageIndex == 0
            ? item.textValue
            : languageIndex == 1
            ? item.traditionalTextValue
            : item.englishTextValue
        "
        disabled
        style="
          position: absolute;
          margin: 0;
          background-repeat: no-repeat;
          background-size: cover;
          background-position: center;
          background-color: transparent;
          border: 0;
          resize: none;
        "
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z + '',
          fontSize: item.fontSize + 'px',
          color: item.fontColor,
        }"
      >
      </textarea>
    </div>

    <div
      v-for="(item, index) in variableSet.threeDList"
      :key="index"
      style="position: absolute; margin: 0"
      :style="{
        width: item.w + 'px',
        height: item.h + 'px',
        left: item.x + 'px',
        top: item.y + 'px',
        zIndex: item.z + '',
      }"
    >
      <div
        :id="'renderCanvas' + index"
        style="width: 90%; height: 90%"
        touch-action="none"
      ></div>
    </div>

    <div v-for="(item, index) in variableSet.imageList" :key="index">
      <img
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        :src="'http://' + resourceIp + ':8094/' + item.src"
        style="
          position: absolute;
          margin: 0;
          background-repeat: no-repeat;
          background-size: cover;
          background-position: center;
          background-color: transparent;
          border: 0;
        "
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z + '',
        }"
        alt=""
      />
    </div>

    <div
      @touchstart="mousePress(index, $event)"
      @mousedown="mousedown(index, $event)"
      @mouseup="mouseUp(index, $event)"
      @touchend="touchEnd(index, $event)"
      style="
        position: absolute;
        margin: 0;
        background: black;
        border: 0;
        z-index: 1;
      "
      :style="{
        left: item.x + 'px',
        top: item.y + 'px',
        zIndex: item.z + '',
      }"
      v-for="(item, index) in variableSet.videoList"
      :key="index"
    >
      <button
        v-if="
          (item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true) && item.videoType == 3
        "
        @click.stop="openKeyborad"
        style="position: absolute; left: 5px; top: 5px; z-index: 2"
      >
        键盘
      </button>
      <button
        v-if="
          (item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true) && item.videoType == 3
        "
        @click.stop="clickRight"
        style="position: absolute; right: 5px; top: 5px; z-index: 2"
      >
        右键
      </button>
      <video
        webkit-playsinline="true"
        x-webkit-airplay="true"
        playsinline="true"
        x5-video-player-type="h5"
        x5-video-orientation="h5"
        x5-video-player-fullscreen="true"
        preload="none"
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        :id="'videoElement' + index"
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
        }"
        autoplay
        :controls="item.videoType == 0"
      >
        <source
          v-if="item.videoType == 0"
          :id="'videoSource' + index"
          :src="variableSet[item.streamVariable]"
          type="video/mp4"
        />
      </video>
    </div>
    <div v-for="(item, index) in variableSet.webPageList" :key="index">
      <iframe
        :src="variableSet[item.webPageUrlVariable]"
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        style="
          position: absolute;
          margin: 0;
          background-repeat: no-repeat;
          background-size: cover;
          background-position: center;
          border: 0;
        "
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z + '',
        }"
        alt=""
      ></iframe>
    </div>
    <div v-for="(item, index) in variableSet.pptList" :key="index">
      <iframe
        :src="
          'https://view.officeapps.live.com/op/embed.aspx?src=' +
          encodeURIComponent(variableSet[item.pptUrlVariable])
        "
        v-if="
          item.conditionShow
            ? variableSet[item.displayVariableName] == item.displayVariableValue
            : true
        "
        style="
          position: absolute;
          margin: 0;
          background-repeat: no-repeat;
          background-size: cover;
          background-position: center;
          border: 0;
        "
        :style="{
          width: item.w + 'px',
          height: item.h + 'px',
          left: item.x + 'px',
          top: item.y + 'px',
          zIndex: item.z + '',
        }"
        alt=""
      ></iframe>
    </div>
    <div
      style="
        position: absolute;
        left: 0;
        bottom: 0px;
        width: 100%;
        display: flex;

        align-items: center;
      "
    >
      <transition name="el-zoom-in-center">
        <div
          v-show="curProgress != null"
          style="padding: 5px 10px; background: #3f8cff; color: white"
        >
          {{ curProgress }}
        </div>
      </transition>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
import request from "../axios/request";
import { Slider, Switch } from "vant";
import "vant/lib/slider/style";
import "vant/lib/switch/style";
import flvjs from "flv.js";
import { mapState } from "vuex";
import * as THREE from "three";
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 引入dat.gui.js的一个类GUI
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import TWEEN from "@tweenjs/tween.js";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
// 引入OutlinePass通道
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
import { GammaCorrectionShader } from "three/examples/jsm/shaders/GammaCorrectionShader.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";

export default {
  components: {
    [Slider.name]: Slider,
    [Switch.name]: Switch,
  },
  data() {
    return {
      idMapFlvJs: {},
      inputForKeyBorad: "",
      pageName: null,
      languageIndex: 0,
      resourceIp: null,
      variableSet: {},
      dynamicWatches: [],
      socket: null,
      tokenId: null,
      lastVideoVariableSet: {},
      lastVideoList: [],
      pageInfo: null,
      buttonVariableSet: null,
      sliderVariableSet: null,
      videoVariableSet: null,
      switchVariableSet: null,
      sliderVariableMap: null,
      flvPlayer: null,
      showKeyBoard: false,
      inputForKeyBoradTop: 0,
      inputForKeyBoradLeft: 0,
      dsBridge: null,
      threeDResourceMap: new Map(),
      MeshArr: [],
      addedMeshMap: new Map(),
      curProgress: null,
    };
  },
  computed: {},

  methods: {
    getinputPosition(event) {
      let canvas = document.getElementById("canvas");
      if (event.target.id.indexOf("videoElement") != -1) {
        let touch = event.changedTouches[0]; // 通常只有一个触摸点

        this.inputForKeyBoradLeft =
          touch.clientX - canvas.getBoundingClientRect().left;
        this.inputForKeyBoradTop =
          touch.clientY - canvas.getBoundingClientRect().top;
      }
    },
    sendWord() {
      let value = this.inputForKeyBorad;
      this.socket.send("inputKeyBoard#" + value);
      this.inputForKeyBorad = "";
    },
    inputKeyBorad(event) {
      if (event.key === "Enter") {
        this.socket.send("inputKeyBoardEnter#");
      } else if (event.key === "Backspace") {
        this.socket.send("inputKeyBoardBackspace#");
      }
    },
    clickRight(event) {
      event.stopPropagation();
      // this.$store.commit("sendMessageBySocket", "clickRight#");
      this.socket.send("clickRight#");
    },
    openKeyborad(event) {
      event.stopPropagation();
      this.showKeyBoard = true;
      this.$nextTick(() => {
        document.getElementById("useKeyborad").focus();
      });
    },
    mouseUp(index, event) {
      if (this.variableSet.videoList[index].videoType != 3) {
        return;
      }
      let sourceId = event.target.id;
      let videoSource = document.getElementById(sourceId);

      this.socket.send(
        "mouseUp#" +
          event.offsetX +
          "-" +
          event.offsetY +
          "-" +
          videoSource.offsetWidth +
          "-" +
          videoSource.offsetHeight
      );
    },
    touchEnd(index, event) {
      if (this.variableSet.videoList[index].videoType != 3) {
        return;
      }
      // 获取触摸事件的目标元素ID
      let sourceId = event.target.id;
      let videoSource = document.getElementById(sourceId);

      // 使用changedTouches来获取触摸点的信息
      let touch = event.changedTouches[0]; // 通常只有一个触摸点
      let offsetX = touch.clientX - videoSource.getBoundingClientRect().left;
      let offsetY = touch.clientY - videoSource.getBoundingClientRect().top;
      this.socket.send(
        "mouseUp#" +
          offsetX +
          "-" +
          offsetY +
          "-" +
          videoSource.offsetWidth +
          "-" +
          videoSource.offsetHeight
      );
    },
    mousedown(index, event) {
      if (this.variableSet.videoList[index].videoType != 3) {
        return;
      }
      let sourceId = event.target.id;
      let videoSource = document.getElementById(sourceId);
      this.socket.send(
        "mousePress#" +
          event.offsetX +
          "-" +
          event.offsetY +
          "-" +
          videoSource.offsetWidth +
          "-" +
          videoSource.offsetHeight
      );
    },
    mousePress(index, event) {
      if (this.variableSet.videoList[index].videoType != 3) {
        return;
      }
      // 触摸事件可能包含多个触摸点，通常我们只处理第一个触摸点
      if (event.touches && event.touches.length > 0) {
        let touch = event.touches[0]; // 获取第一个触摸点
        let sourceId = event.target.id;
        let videoSource = document.getElementById(sourceId);

        // 使用 touch 对象的 clientX 和 clientY 来获取触摸位置
        // 如果需要相对于元素的偏移，可以计算如下（需要元素的 getBoundingClientRect）
        let rect = videoSource.getBoundingClientRect();
        let offsetX = touch.clientX - rect.left;
        let offsetY = touch.clientY - rect.top;
        this.socket.send(
          "mousePress#" +
            offsetX +
            "-" +
            offsetY +
            "-" +
            videoSource.offsetWidth +
            "-" +
            videoSource.offsetHeight
        );
      }
    },
    disConnectPage() {
      this.socket.send("disconnect#" + this.pageName + "#" + this.tokenId);
    },
    submitWS() {
      this.$nextTick(() => {
        this.socket.send("connect#" + this.pageName + "#" + this.tokenId);
      });
    },
    async onInput(index) {
      if (this.curProgress != null) {
        return;
      }
      this.curProgress = '开始执行命令'
      let item = this.variableSet.switchList[index];

      let res = await request({
        url: "/command/api/executeCommand",
        method: "POST",
        data: {
          type: item.type,
          id: item.id,
          variableSet: this.variableSet,
          wsToken: this.tokenId,
        },
      });
    },
    checkVideo() {
      if (
        this.variableSet.videoList == null ||
        this.variableSet.videoList.length == 0
      ) {
        return;
      }

      for (let index = 0; index < this.variableSet.videoList.length; index++) {
        const element = this.variableSet.videoList[index];
        console.log("当前视频类型为：" + element.videoType);
        let newUrl = this.variableSet[element.streamVariable];
        console.log("当前视频的视频源为：" + newUrl);
        if (element.conditionShow == true) {
          if (
            this.variableSet[element.displayVariableName] !=
              element.displayVariableValue &&
            element.show == true
          ) {
            this.destroyVideo(index);
            element.show = false;
            return;
          }
          if (
            this.variableSet[element.displayVariableName] ==
              element.displayVariableValue &&
            element.show == false
          ) {
            element.url = newUrl;
            element.show = true;
            this.createVideo(index, newUrl);

            return;
          }
        }
        if (newUrl == element.url) {
          return;
        }
        console.log("新视频源与旧视频源不相等");

        this.destroyVideo(index);
        element.url = newUrl;
        console.log("开始播放");
        this.createVideo(index, newUrl);
      }
    },
    destroyVideo(index) {
      const element = this.variableSet.videoList[index];
      if (element.videoType == 0) {
        const videoElement = document.getElementById("videoElement" + index);
        videoElement.pause();
        videoElement.src = "";
        videoElement.load(); // 强制释放资源[1,6](@ref)
      }
      if (element.videoType == 1 || element.videoType == 3) {
        let flvPlayer = this.idMapFlvJs[index];
        if (flvPlayer == null) {
          return;
        }

        flvPlayer.pause();
        flvPlayer.unload();
        flvPlayer.detachMediaElement();
        flvPlayer.destroy();
        flvPlayer = null;
      }
    },
    switchValue() {},
    extractIPFromURL(url) {
      // 定义正则表达式来匹配IP地址
      const ipRegex = /(?:\d{1,3}\.){3}\d{1,3}/;

      // 使用正则表达式查找匹配项
      const match = url.match(ipRegex);

      // 返回匹配到的IP地址（如果有的话）
      return match ? match[0] : null;
    },
    changeValueType() {
      for (let key in this.sliderVariableMap) {
        this.variableSet[key] = Number(this.variableSet[key]);
        this.variableSet[this.sliderVariableMap[key]] = Number(
          this.variableSet[this.sliderVariableMap[key]]
        );
      }
    },
    async initPage() {
      await request({
        url: "/page/api/initPage/" + this.pageName + "/" + this.tokenId,
        method: "POST",
        data: {
          variableSet: this.variableSet,
        },
      });
    },
    playVideoByType() {
      if (
        this.variableSet.videoList == null ||
        this.variableSet.videoList.length == 0
      ) {
        return;
      }
      for (let index = 0; index < this.variableSet.videoList.length; index++) {
        const element = this.variableSet.videoList[index];
        if (element.conditionShow == true) {
          if (
            this.variableSet[element.displayVariableName] !=
            element.displayVariableValue
          ) {
            element.show = false;
          } else {
            element.show = true;
            return;
          }
        }
        let url = this.variableSet[element.streamVariable];
        element.url = url;
        if (element.videoType == 1 || element.videoType == 3) {
          this.createVideo(index, url);
        } else if (element.videoType == 0) {
          // 播放视频
          this.playVideo(index, url);
        }
      }
    },
    playVideo(index, curUrl) {
      this.$nextTick(() => {
        let videoElement = document.getElementById("videoElement" + index);
        let videoSource = document.getElementById("videoSource" + index);
        videoSource.src = curUrl;
        videoElement.load();
        videoElement.play();
      });
    },
    createVideo(index, curUrl) {
      this.$nextTick(() => {
        const element = this.variableSet.videoList[index];
        let videoElement = document.getElementById("videoElement" + index);
        console.log(element.videoType);
        console.log(videoElement);
        console.log("当前元素的视频地址:" + curUrl);
        if (element.videoType == 0) {
          console.log("开始播放");
          videoElement.src = curUrl;
          videoElement
            .play()
            .then(() => console.log("播放成功"))
            .catch((error) => {
              console.error("自动播放被阻止，需要用户交互:", error);
              // 可以显示一个播放按钮，让用户手动触发
            });
        }
        if (element.videoType == 1 || element.videoType == 3) {
          let flvPlayer = null;

          if (flvjs.isSupported()) {
            flvPlayer = flvjs.createPlayer(
              {
                type: "flv",
                isLive: true,
                hasAudio: false,
                url: curUrl,
              },
              {
                enableWorker: false, //不启用分离线程
                enableStashBuffer: false, //关闭IO隐藏缓冲区
                reuseRedirectedURL: true, //重用301/302重定向url，用于随后的请求，如查找、重新连接等。
                autoCleanupSourceBuffer: true, //自动清除缓存
              }
            );
            if (flvPlayer != null) {
              this.idMapFlvJs[index] = flvPlayer;

              flvPlayer.attachMediaElement(videoElement);

              if (curUrl !== "" && curUrl !== null) {
                flvPlayer.load();
                flvPlayer.play();
              }
            }
          }

          //定时方法是为了用户离开页面视频是实时播放的,暂停按钮无用
          setInterval(function () {
            if (videoElement.buffered.length > 0) {
              const end = videoElement.buffered.end(0); // 视频结尾时间
              const current = videoElement.currentTime; //  视频当前时间
              const diff = end - current; // 相差时间
              const diffCritical = 4; // 这里设定了超过4秒以上就进行跳转
              const diffSpeedUp = 1; // 这里设置了超过1秒以上则进行视频加速播放
              const maxPlaybackRate = 4; // 自定义设置允许的最大播放速度
              let playbackRate = 1.0; // 播放速度
              if (diff > diffCritical) {
                videoElement.currentTime = end - 1.5;
                playbackRate = Math.max(1, Math.min(diffCritical, 16));
              } else if (diff > diffSpeedUp) {
                playbackRate = Math.max(1, Math.min(diff, maxPlaybackRate, 16));
              }
              videoElement.playbackRate = playbackRate;
              if (videoElement.paused) {
                videoElement.play();
              }
            }
          }, 1000);

          flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => {
            if (flvPlayer) {
              this.reloadVideo(flvPlayer);
            }
          });
        }
      });
    },
    async executeCommandForAudio(audioStr) {
      if (this.curProgress != null) {
        return;
      }
      this.curProgress = '开始执行命令'
      let res = await request({
        url: "/command/api/executeCommand",
        method: "POST",
        data: {
          type: "AUDIO",
          pageId: this.pageInfo.id,
          variableSet: this.variableSet,
          audioContent: audioStr,
          wsToken: this.tokenId,
        },
      });
    },
    async executeCommandForClick(item) {
      if (this.curProgress != null) {
        return;
      }
      this.curProgress = '开始执行命令'
      let res = await request({
        url: "/command/api/executeCommand",
        method: "POST",
        data: {
          type: item.type,
          id: item.id,
          variableSet: this.variableSet,
          wsToken: this.tokenId,
        },
      });
    },
    async executeCommandForClickVideo(index) {
      if (this.curProgress != null) {
        return;
      }
      this.curProgress = '开始执行命令'
      let res = await request({
        url: "/command/api/executeCommand",
        method: "POST",
        data: {
          type: "video",
          id: this.variableSet.videoList[index].id,
          variableSet: this.variableSet,
          wsToken: this.tokenId,
        },
      });
    },
    async changeSlider(item) {
      if (this.curProgress != null) {
        return;
      }
      this.curProgress = '开始执行命令'
      let res = await request({
        url: "/command/api/executeCommand",
        method: "POST",
        data: {
          type: item.type,
          id: item.id,
          variableSet: this.variableSet,
          wsToken: this.tokenId,
        },
      });
    },
    init() {
      this.sliderVariableSet.forEach((value) => {
        this.$set(this.variableSet, value, null);
      });
      this.buttonVariableSet.forEach((value) => {
        this.$set(this.variableSet, value, null);
      });
      this.videoVariableSet.forEach((value) => {
        this.$set(this.variableSet, value, null);
      });
      this.switchVariableSet.forEach((value) => {
        this.$set(this.variableSet, value, null);
      });
      this.initPage();
    },
    async getAllComponent(needInit) {
      let res = await request({
        url:
          "/page/api/getAllComponentByPageName/" +
          this.pageName +
          "/" +
          document.documentElement.clientWidth +
          "/" +
          document.documentElement.clientHeight +
          "/true",
        method: "GET",
      });
      if (res.data.status == 200) {
        this.variableSet = {};
        this.variableSet["pageSourceWidth"] = this.pageInfo.pageWidth;
        this.variableSet["pageSourceHeight"] = this.pageInfo.pageHeight;
        this.variableSet["pageRealWidth"] =
          document.documentElement.clientWidth;
        this.variableSet["pageRealHeight"] =
          document.documentElement.clientHeight;
        this.variableSet["buttonList"] = res.data.data.buttonList;
        this.variableSet["sliderList"] = res.data.data.sliderList;
        this.variableSet["textViewList"] = res.data.data.textViewList;
        this.variableSet["switchList"] = res.data.data.switchList;
        this.variableSet["imageList"] = res.data.data.imageList;
        this.variableSet["videoList"] = res.data.data.videoList;
        this.variableSet["webPageList"] = res.data.data.webPageList;
        this.variableSet["pptList"] = res.data.data.pptList;
        this.variableSet["threeDList"] = res.data.data.threeDList;
        this.buttonVariableSet = new Set(res.data.data.buttonVariableSet);
        this.sliderVariableSet = new Set(res.data.data.sliderVariableSet);
        this.videoVariableSet = new Set(res.data.data.videoVariableSet);
        this.switchVariableSet = new Set(res.data.data.switchVariableSet);
        this.sliderVariableMap = res.data.data.sliderVariableMap;

        if (needInit) {
          this.init3DScenes();
          this.init();
        }
      }
    },
    init3DScenes() {
      this.$nextTick(() => {
        let threeDSceneArr = this.variableSet["threeDList"];
        for (let index = 0; index < threeDSceneArr.length; index++) {
          const element = threeDSceneArr[index];
          let canvas = document.getElementById("renderCanvas" + index);
          const scene = new THREE.Scene();

          // 创建相机
          const camera = new THREE.PerspectiveCamera(
            50,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
          );
          camera.position.set(10, 10, 10); // 设置相机位置
          camera.lookAt(0, 0, 0); // 设置相机看向原点

          // 创建渲染器
          const renderer = new THREE.WebGLRenderer({
            antialias: true,
          });
          renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);
          renderer.setClearColor(0x000000, 0);

          canvas.appendChild(renderer.domElement);
          // 将渲染结果添加到目标元素
          // 设置相机控件轨道控制器OrbitControls
          const controls = new OrbitControls(camera, renderer.domElement);
          // 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
          controls.addEventListener("change", function () {
            renderer.render(scene, camera); //执行渲染操作
          }); //监听鼠标、键盘事件

          // 平行光
          const directionalLight = new THREE.DirectionalLight(0xffffff, 5);
          // 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
          directionalLight.position.set(20, 20, 20);

          scene.add(directionalLight);

          const dirLightHelper = new THREE.DirectionalLightHelper(
            directionalLight,
            5,
            0xff0000
          );
          scene.add(dirLightHelper);

          const raycaster = new THREE.Raycaster();
          const mouse = new THREE.Vector2();
          // 创建后处理对象EffectComposer，WebGL渲染器作为参数
          const composer = new EffectComposer(renderer);
          const renderPass = new RenderPass(scene, camera);
          // 设置renderPass通道
          composer.addPass(renderPass);
          //           const gammaCorrectionShader = new ShaderPass(GammaCorrectionShader);
          // composer.addPass(gammaCorrectionShader);
          // OutlinePass第一个参数v2的尺寸和canvas画布保持一致
          const v2 = new THREE.Vector2(canvas.offsetWidth, canvas.offsetHeight);
          // const v2 = new THREE.Vector2(800, 600);
          const outlinePass = new OutlinePass(v2, scene, camera);
          outlinePass.pulsePeriod = 2;
          composer.addPass(outlinePass);

          let _ = require("lodash");
          // 点击事件处理函数
          const handleClick = (event) => {
            // 将鼠标点击位置归一化为设备坐标 (-1 到 +1)
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

            // 通过相机和鼠标位置更新射线
            raycaster.setFromCamera(mouse, camera);

            // 计算射线与模型的交点
            const intersects = raycaster.intersectObjects(scene.children);

            if (intersects.length > 0) {
              // 获取被点击的模型
              const clickedModel = intersects[0].object;
              outlinePass.selectedObjects = [clickedModel];
            }
          };
          // 添加点击事件监听
          window.addEventListener("dblclick", _.debounce(handleClick, 300));

          threeDSceneArr[index].renderer = renderer;
          threeDSceneArr[index].scene = scene;
          threeDSceneArr[index].camera = camera;
          threeDSceneArr[index].controls = controls;
          // 加载模型到内存
          this.loadModel(element.sourceList, scene, camera, element.meshList);

          function animate() {
            composer.render();
            // renderer.render(scene, camera);
            requestAnimationFrame(animate);
          }
          animate();
        }
      });
    },
    loadModel(sourceList, scene, camera, meshList) {
      let loadedModelNum = 0;
      const that = this;
      for (let index = 0; index < sourceList.length; index++) {
        const element = sourceList[index];
        if (this.threeDResourceMap.has(element)) {
          loadedModelNum++;
          continue;
        }
        const loader = new GLTFLoader();
        loader.load(
          element,
          function (gltf) {
            that.threeDResourceMap.set(element, gltf);
            loadedModelNum++;
            that.$message({
              message: element + "加载成功",
              type: "success",
            });
            //  检查是否所有模型已加载
            if (loadedModelNum == sourceList.length) {
              that.drawMeshes(scene, camera, meshList);
            }
          },
          function (xhr) {
            // 控制台查看加载进度xhr
            // 通过加载进度xhr可以控制前端进度条进度
            const percent = xhr.loaded / xhr.total;
            console.log("加载进度" + percent);
          }
        );
      }
    },
    drawMeshes(scene, camera, meshList) {
      for (let index = 0; index < meshList.length; index++) {
        const element = meshList[index];
        if (this.addedMeshMap.has(element.sourcePath + "*" + element.name)) {
          let obj = this.addedMeshMap.get(
            element.sourcePath + "*" + element.name
          );
          let clonedObj = obj.clone(true);

          // 如果需要克隆材质，可以单独处理
          // clonedObj.material = obj.material.clone();
          // clonedObj.geometry = obj.geometry.clone();
          // 将克隆的对象添加到场景中
          scene.add(clonedObj);
          this.addedMeshMap.set(
            element.sourcePath + "*" + element.name,
            clonedObj
          );
          clonedObj.position.set(
            element.positionX,
            element.positionY,
            element.positionZ
          );
          clonedObj.scale.set(
            element.scalingX,
            element.scalingY,
            element.scalingZ
          );
          clonedObj.quaternion.x = element.rotationX;
          clonedObj.quaternion.y = element.rotationY;
          clonedObj.quaternion.Z = element.rotationZ;
          // 将克隆的对象记录到 MeshArr 中
          this.MeshArr.push({
            name: "model" + this.MeshArr.length,

            mesh: clonedObj,
          });
          continue;
        }

        let curGltf = this.threeDResourceMap.get(element.sourcePath);

        const that = this;
        try {
          curGltf.scene.traverse(function (obj) {
            if (obj.isMesh && obj.name === element.name) {
              scene.add(obj);
              that.addedMeshMap.set(
                element.sourcePath + "*" + element.name,
                obj
              );
              obj.position.set(
                element.positionX,
                element.positionY,
                element.positionZ
              );
              obj.scale.set(
                element.scalingX,
                element.scalingY,
                element.scalingZ
              );
              obj.quaternion.x = element.rotationX;
              obj.quaternion.y = element.rotationY;
              obj.quaternion.Z = element.rotationZ;
              that.MeshArr.push({
                name: "model" + that.MeshArr.length,
                mesh: obj,
              });
            }
          });
        } catch (error) {}

        console.log("已添加" + (index + 1) + "个组件");
      }

      this.variableSet["threeDList"][0].controls.target.set(
        this.MeshArr[0].mesh.position.x,
        this.MeshArr[0].mesh.position.y,
        this.MeshArr[0].mesh.position.z
      );
      this.variableSet["threeDList"][0].controls.update();
    },
    sendTokenToAndroid() {
      this.dsBridge.call("getTokenId", this.tokenId);
    },
    sendCloseToAndroid() {
      this.dsBridge.call("closeWindow", null);
    },
    sendDataToAndroid() {
      let change = false;
      this.videoVariableSet.forEach((value) => {
        if (this.lastVideoVariableSet[value] != this.variableSet[value]) {
          change = true;
          this.lastVideoVariableSet[value] = this.variableSet[value];
        }
      });
      if (!change) {
        let _ = require("lodash");
        for (
          let index = 0;
          index < this.variableSet.videoList.length;
          index++
        ) {
          const element = this.variableSet.videoList[index];
          if (_.isEqual(element, this.lastVideoList[index]) == false) {
            change = true;
          }
        }
        this.lastVideoList = this.variableSet.videoList;
      }

      if (!change) {
        return;
      }
      let param = {
        videoList: this.variableSet.videoList,
        webWidth: document.documentElement.clientWidth,
        webHeight: document.documentElement.clientHeight,
        dataList: this.lastVideoVariableSet,
      };
      console.log("开始发送");
      this.dsBridge.call("getAppData", param);
    },
    async getPageInfoByPageName(needInit) {
      let res = await request({
        url: "/page/api/getPageInfoByPageName/" + this.pageName,
        method: "GET",
      });
      if (res.data.status == 200) {
        this.pageInfo = res.data.data;
        this.getAllComponent(needInit);
      }
    },
    async connectWs() {
      var resOfGetRandomId = await request({
        url: "/language/api/getRandomId",
        method: "GET",
      });
      if (resOfGetRandomId.data.status == 200 && this.tokenId == null) {
        this.tokenId = resOfGetRandomId.data.data;
        this.sendTokenToAndroid();
        this.initWs(resOfGetRandomId.data.data);
      }
    },
    initWs(wsId) {
      if (typeof WebSocket === "undefined") {
        alert("您的浏览器不支持socket");
      } else {
        let wsUrl = window.location.origin.replace("http://", "");
        // 实例化socket 111是固定的用户id,正式环境直接获取当前登录用户id
        // this.socket = new WebSocket(
        //   "ws:" + "192.168.0.62:8094" + "//wsServer/" + wsId
        // );
        this.socket = new WebSocket("ws:" + wsUrl + "//wsServer/" + wsId);
        this.global.setWs(this.socket);
        let that = this;
        // 监听socket连接
        this.socket.onopen = () => {
          console.log("socket连接成功");
          that.socket.send("connect#" + that.pageName + "#" + that.tokenId);
          this.getPageInfoByPageName(true);
        };
        // 监听socket错误信息
        this.socket.onerror = () => {
          console.error("连接错误");
        };
        //监听socket消息
        this.socket.onmessage = (msg) => {
          let jsonObject = JSON.parse(msg.data);
          console.log(jsonObject);
          if (jsonObject.data.type == "refresh") {
            that.getPageInfoByPageName(false);
          } else if (jsonObject.data.type == "commandResult") {
            this.curProgress =
              "执行中，已执行第" + jsonObject.data.progress + "个命令";
            for (let key in jsonObject.data.data) {
              this.variableSet[key] = jsonObject.data.data[key];
              if (this.sliderVariableSet.has(key)) {
                console.log(key);
                let oldValueVariable = this.sliderVariableMap[key];
                console.log(this.sliderVariableMap);
                if (oldValueVariable != null) {
                  console.log(oldValueVariable);
                  jsonObject.data.data[oldValueVariable] =
                    jsonObject.data.data[key];
                  console.log("oldValuebleSet:" + jsonObject.data.data[key]);
                }
              }
            }
            console.log(this.variableSet);
            this.changeValueType();
            // 检验video组件 是否改变
            this.checkVideo();
            this.sendDataToAndroid();
          } else if (jsonObject.data.type == "message") {
            console.log("消息");
            console.log(jsonObject);
            this.$message({
              message: jsonObject.data.data,
              type: "success",
            });
          } else if (jsonObject.data.type == "presetMessage") {
            this.variableSet[jsonObject.data.key] = jsonObject.data.data;
            console.log(jsonObject.data.data);
          } else if (jsonObject.data.type == "endProgress") {
            this.curProgress = "执行完成";
            const timer1 = setTimeout(() => {
              this.curProgress = null;
              clearTimeout(timer1);
            }, 1000);
          }
          this.$forceUpdate();
        };
        // 监听socket关闭信息
        this.socket.onclose = (e) => {
          console.log("socket已经关闭");
        };
      }
    },
  },
  mounted() {
    let that = this;
    if (window.cefQuery) {
      console.log("支持cef通信");
    } else {
      console.log("不支持cef通信");
    }
    this.resourceIp = this.extractIPFromURL(window.location.origin);
    this.languageIndex = Number(this.$route.params.language);
    this.pageName = this.$route.params.pageName;
    this.dsBridge = require("dsbridge");
    this.dsBridge.register("sendAudioCommand", function (data) {
      that.executeCommandForAudio(data);
    });
    this.dsBridge.register("videoClickCommand", function (data) {
      that.executeCommandForClickVideo(data);
    });
    window.onload = function () {
      document.addEventListener("touchstart", function (event) {
        if (event.touches.length > 1) {
          event.preventDefault();
        }
      });
    };
    this.connectWs();
  },
  beforeDestroy() {
    for (let index = 0; index < this.variableSet.videoList.length; index++) {
      let flvPlayer = this.idMapFlvJs[index];

      flvPlayer.pause();
      flvPlayer.unload();
      flvPlayer.detachMediaElement();
      flvPlayer.destroy();
      flvPlayer = null;
    }
    this.socket.send("disconnect#" + this.pageName + "#" + tokenId);
    this.socket.close();
    this.socket = null;
    // this.sendCloseToAndroid();
  },
};
</script>

<style scoped>
.MyButton:active {
  transform: scale(0.9);
  transition: transform 0.3s ease;
}
</style>
